#define _USE_MATH_DEFINES

#include <cstdio>
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <cassert>
#include <stack>
#include <cstdlib>
#include <bitset>
#include <cmath>

#define forn(i,n) for (int i = 0; i < int(n); ++i)
#define pb push_back
#define all(a) a.begin(),a.end()
#define sz(a) int(a.size())
#define mp make_pair

using namespace std;

typedef long long li;
typedef long double ld;

typedef pair<int,int> pt;
#define ft first
#define sc second

const int INF = int(1e9);
const li INF64 = li(1e18);
const ld EPS = 1e-9;

//#define TASK_NAME ""

const int N = 5 * 1000 + 5;

int n, m;
vector <pt> g[N];

bool read() {
	if (scanf("%d %d", &n, &m) != 2)
		return false;
	forn(i, m) {
		int a, b;
		scanf("%d %d", &a, &b);
		--a, --b;
		g[a].pb(mp(b, i));
		g[b].pb(mp(a, i));
	}
	return true;
}

int tin[N], T, fup[N];

li was;
li res;

set <int> rev[N];
int f[N], q[N], h[N];

void inc(int *f, int pos) {
	for (; pos < N; pos |= pos + 1)
		f[pos]++;
}

int get(int* f, int r) {
	int res = 0;
	for (; r >= 0; r = (r & (r + 1)) - 1)
		res += f[r];
	return res;
}

vector <int> e[N];

int get_minr(int v, int l) {
	int res = INF;
	set<int>::iterator it = rev[v].lower_bound(l);
	if (it != rev[v].end())
		res = min(res, *it);

	forn(i, sz(e[v]))
		res = min(res, get_minr(e[v][i], l));
	return res;
}

void move_down(int v, int up, int l, int &r, int &res) {
	int cnt = 0, lst = -1;
	forn(i, sz(e[v])) {
		if (fup[ e[v][i] ] <= up) {
			cnt++;
			lst = e[v][i];
		}
	}

	if (!rev[v].empty() && *rev[v].begin() <= up)
		cnt = 5;

	if (cnt == 1) {
		move_down(lst, up, l, r, res);
		if (tin[v] < r)
			res++;
		else {
			set<int>::iterator it = rev[v].lower_bound(l);
			if (it != rev[v].end())
				r = min(r, *it);
			res = 0;
		}
		return;
	}

	r = get_minr(v, l);
	res = 0;
}

void dfs(int v, int from) {

	tin[v] = fup[v] = T++;

	forn(i, sz(g[v])) {
		int to = g[v][i].ft;
		int id = g[v][i].sc;

		if (id == from)
			continue;

		if (tin[to] != -1 && tin[to] < tin[v]) {
			fup[v] = min(fup[v], tin[to]);
			inc(f, tin[to]);
			rev[v].insert(tin[to]);
			continue;
		}

		if (tin[to] != -1)
			continue;

		int oldf = get(f, tin[v]);

		e[v].pb(to);
		dfs(to, id);

		int deltaf = get(f, tin[v]) - oldf;

		if (fup[to] > tin[v]) {
			res += m - 1;
			was++;
		} else {
			if (deltaf == 1)
				res ++;

			int r = tin[to];
			int cur = 0;
			move_down(to, tin[v], tin[to], r, cur);
			res += cur;
		}

		fup[v] = min(fup[v], fup[to]);
	}
}

void solve() {
	memset(tin, -1, sizeof(tin));
	dfs(0, -1);
	res -= was * (was - 1) / 2;
	cout << res << endl;
}

int main() {
#ifdef TASK_NAME
	freopen(TASK_NAME ".in", "r", stdin);
	freopen(TASK_NAME ".out", "w", stdout);
#endif

#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#endif

	while (read())
		solve();

	return 0;
}